﻿using Log.Recorder.Entity;
using System.Collections.Generic;
using System.Threading;

namespace Log.Recorder
{
    class LogWriter
    {

        private static LogWriter writer = new LogWriter();
        /// <summary>
        /// 静态示例
        /// </summary>
        public static LogWriter StaticInstance { get { return writer; } }

        /// <summary>
        /// 日志池
        /// </summary>
        private Queue<LogContent> logPool;
        public LogWriter()
        {
            logPool = new Queue<LogContent>();
        }
        /// <summary>
        /// 日志池大小
        /// </summary>
        public int LogCount
        {
            get
            {
                return logPool.Count;
            }
        }

        #region 写日志到队列

        /// <summary>
        /// 写日志到队列
        /// </summary>
        /// <param name="logInfo"></param>
        public void AddToLogPool(LogContent content)
        {
            if (string.IsNullOrEmpty(content.LogFileName))
            {
                return;
            }
            //线程初始化
            ThreadInit();

            logPool.Enqueue(content);
        }

        #endregion

        #region 写日志线程处理

        /// <summary>
        /// 线程初始化
        /// </summary>
        public void ThreadInit()
        {
            //线程初始化
            if (!IsInit)
            {
                Thread thread = new Thread(WriterWork);
                thread.Name = "LogRecorderPool_Thread";
                thread.IsBackground = true;
                thread.Start();

                IsInit = true;
            }
        }
        /// <summary>
        /// 是否线程初始化
        /// </summary>
        public bool IsThreadInit
        {
            get { return IsInit; }
        }
        /// <summary>
        /// 是否初始化
        /// </summary>
        private bool IsInit = false;
        private object locker = new object();
        /// <summary>
        /// 日志写入数据库
        /// </summary>
        private void WriterWork()
        {
            while (true)
            {
                lock (locker)
                {
                    List<LogContent> errorContents = new List<LogContent>();
                    try
                    {
                        if (logPool.Count > 0)
                        {

                            Dictionary<string, LogContentGroup> logDIC = new Dictionary<string, LogContentGroup>();
                            int queueCount = 1000;
                            for (int ind = 0; ind < queueCount; ind++)
                            {
                                if (logPool.Count > 0)
                                {
                                    LogContent _content = logPool.Dequeue();
                                    if (!logDIC.ContainsKey(_content.LogFileName))
                                    {
                                        LogContentGroup logGroup = new LogContentGroup();
                                        ////2021\\06\\03\\20210603_debug.db
                                        //logGroup.logFilePath = string.Format("{0}\\{1}\\{2}.db"
                                        //    , _content.Time.ToString("yyyy")
                                        //    , _content.Time.ToString("MM")
                                        //    , _content.LogFileName
                                        //);
                                        logGroup.logFilePath = _content.LogFileName;
                                        logDIC[_content.LogFileName] = logGroup;
                                    }
                                    logDIC[_content.LogFileName].LogContents.Add(_content);
                                }
                                else
                                {
                                    break;
                                }
                            }

                            foreach (KeyValuePair<string, LogContentGroup> kvp in logDIC)
                            {
                                DbWriter _write = null;
                                try
                                {
                                    //写入数据库
                                    _write = DbWriterPool.GetOrCreateLogWriter(kvp.Value.logFilePath);
                                    _write.IsLogging = true;
                                    _write.Write(kvp.Value.LogContents);
                                    _write.IsLogging = false;

                                    // 记录器不在池中时，释放资源
                                    if (!DbWriterPool.IsHasWriter(kvp.Value.logFilePath)) {
                                        _write.Dispose();
                                        _write = null;
                                    }
                                }
                                catch
                                {
                                    if (_write != null) {
                                        _write.IsLogging = false;
                                    }
                                    errorContents.AddRange(kvp.Value.LogContents);
                                }
                            }

                            //线程睡50毫秒，让资源给数据库读取操作
                            Thread.Sleep(50);
                        }
                        else
                        {
                            //若无数据，让线程睡1000毫秒,之后进入下一轮循环
                            Thread.Sleep(1000);
                        }

                        //销毁过期日志器
                        DbWriterPool.DestroyLogWriter();
                    }
                    catch
                    {
                        //异常，重新入队
                        if (errorContents.Count > 0)
                        {
                            foreach (LogContent content in errorContents)
                            {
                                logPool.Enqueue(content);
                            }
                        }
                    }
                    finally
                    {
                        errorContents = null;
                    }
                }
            }
        }

        #endregion



        public class LogContentGroup
        {

            public string logFilePath { get; set; }
            public List<LogContent> LogContents { get; set; }
            public LogContentGroup()
            {
                LogContents = new List<LogContent>();
            }
        }







    }
}
